#include "types.h"
#include "user.h"
#include "fcntl.h"

int numofdigits(int n) {

	int r, count;

	if (n == 0) {
		return 1;
	}

	r = n;
	if (r < 0) {
		r = r * -1;
	}

	count = 0;
	while (r > 0) {
		count++;
		r = r / 10;
	}

	return count;
}

int calcFileFibonacci(int n, int cid){

	int i, current, previous1, previous2, fd;
	char previous1String[100], previous2String[100];
	char* cidString = 0;
	cidString = malloc(numofdigits(cid) + 1);
	itoa(cid, cidString);
	char* fibFile = 0;

	//create a file per process "FibTest<cid>.txt"
	*fibFile = '\0';
	strcat(fibFile, "FibTest");
	strcat(fibFile, cidString);
	strcat(fibFile, ".txt");

	//initialize variables
	previous1 = 0;
	previous2 = 1;
	current = 1;


	if(n < 0){
		free(cidString);
		return -1;
	}
	else if(n == 0){
		free(cidString);
		return 0;
	}
	else if(n == 1){
		free(cidString);
		return 1;
	}

	//first, open/create file
	if((fd = open(fibFile, O_CREATE | O_RDWR)) < 0){
		  printf(2, "cannot create %s\n", fibFile);
		  free(cidString);
		  exit();
	}
	//second, write starting variables and close
	printf(fd, "%d\n", previous1);
	printf(fd, "%d\n", previous2);
	close(fd);

	//third, calculate fibonacci n by
	//opening file, reading current values, converting from string to int
	//calculating the next values, writing back to file, and printing to stdout
	for (i = 2; i <= n; i++) {

		if((fd = open(fibFile, O_RDONLY)) < 0){
		  printf(2, "cannot open %s\n", fibFile);
		  exit();
		}

//		read(fd, &previous1String, 100);
//		read(fd, &previous2String, 100);

		fgets(fd, previous1String, 100);
		fgets(fd, previous2String, 100);

		previous1String[strlen(previous1String) - 1] = '\0';
		previous2String[strlen(previous2String) - 1] = '\0';
		close(fd);

		previous1 = atoi(previous1String);
		previous2 = atoi(previous2String);

		current = previous1 + previous2;
		previous1 = previous2;
		previous2 = current;

		if((fd = open(fibFile, O_CREATE | O_RDWR)) < 0){
		  printf(2, "cannot create %s\n", fibFile);
		  exit();
		}
		printf(fd, "%d\n", previous1);
		printf(fd, "%d\n", previous2);
		close(fd);

		printf(1, "FibTest %d %d,%d\n", cid, previous2, previous1);
	}

	//delete fibonaaci files
    if(unlink(fibFile) < 0){
      printf(2, "failed to delete %s\n", fibFile);
    }

	free(cidString);
	return current;
}


int calcLocalFibonacci(int n){
	int i;
	int fib = 0;

	if(n < 0)
		return -1;
	else if(n == 0)
		return 0;
	else if(n == 1)
		return 1;
	else{
		for(i = 2; i <= n; i++){
			fib+= (i - 1) + (i - 2);
		}
	}
	return fib;
}

int
main(int argc, char *argv[]){

	if(argc != 2){
		printf(1, "usage: %s number\n", argv[0]);
		exit();
	}

	struct {
		int pid;
		int wtime;
		int rtime;
		int tatime;
	}children[30];

	int n = atoi(argv[1]);
	int i,j;
	int pid;

	int wtime;//parameter to pass to wait2
	int rtime;//parameter to pass to wait2

	int total_wtime = 0;
	int total_rtime = 0;
	int total_tatime = 0;

	for(i = 0; i < 30; i++){
		children[i].pid = fork();
		if(children[i].pid == 0 && ((i % 2) == 0)){//an even numbered child
			calcFileFibonacci(n, i);
			exit();
		}
		else if(children[i].pid == 0 && ((i % 2) == 1)){//an odd numbered child
			calcLocalFibonacci(n);
			exit();
		}

	    printf(1, "FibTest: proc %d finished its calculation\n", i);
	}

//the parent iterates and waits for it's children
//summing up the total waiting time and total running time
//each child saves it's statistics to be printed later on
	for(i = 0; i < 30; i++){
		pid = wait2(&wtime, &rtime);

		for (j = 0; j < 30; j++){
		  if (children[j].pid == pid) {
			children[j].wtime = wtime;
			children[j].rtime = rtime;
			children[j].tatime = wtime + rtime;
			break;
		  }
		}
		total_wtime += wtime;
		total_rtime += rtime;
	}

//parent calculates total turnaround time
//and prints the average statistics
		total_tatime = total_wtime + total_rtime;
		printf(1, "Average waiting time: %d\n", total_wtime / 30);
		printf(1, "Average running time: %d\n", total_rtime / 30);
		printf(1, "Average turnaround time: %d\n", total_tatime / 30);

//parent iterates and prints each child's statistics
//and exits when done
		for(i = 0; i < 30; i++){
			printf(1, "child: %d", i);
			//printf(1, " priority: %d", children[i].priority);
			printf(1, " pid: %d", children[i].pid);
			printf(1, " waiting time: %d", children[i].wtime);
			printf(1, " running time: %d", children[i].rtime);
			printf(1, " turnaround time: %d\n", children[i].tatime);
		}
	 exit();
}

